/****************************************************************
 * <strong>MFDataTree数据树</strong>
 * <p>
 * 数据树
 * </p>
 *
 * @author AndyZhang 2011
 * @version 0.1
 * ToDo:
 ***************************************************************/

package com.thinkwide.data.vdata;

import com.thinkwide.data.core.MFString;
import com.thinkwide.data.ormapping.MFReflect;
import com.thinkwide.data.ormapping.datatable.MFDataRow;
import com.thinkwide.data.ormapping.datatable.MFDataTable;

import java.util.ArrayList;
import java.util.List;

public class MFDataTree {
    private MFDataNodes nodeList;
    private MFDataNode root;
    private String parentProperty = "";
    private String idProperty = "";
    private String textProperty = "";
    private String dataProperty = "";
    private String tagProperty = "";

    public MFDataTree() {
        nodeList = new MFDataNodes();
        root = new MFDataNode();
    }

    public List<MFDataNode> getAllChildList(String id) {
        List<MFDataNode> clist = new ArrayList<MFDataNode>();
        MFDataNode node = findNode(id);
        recursiveTree(clist, node);
        return clist;
    }

    public MFDataNode findNode(String id) {
        List<MFDataNode> clist = new ArrayList<MFDataNode>();
        recursiveTree(clist, root);
        for (MFDataNode item : clist) {
            if (MFString.compareCase(item.getId(), id)) {
                return item;
            }
        }

        return null;
    }

    public void recursiveTree(List<MFDataNode> nodeList, MFDataNode node) {
        for (MFDataNode item : node.getChilds()) {
            nodeList.add(item);

            if (item.getChilds().size() > 0) recursiveTree(nodeList, item);

        }

    }

    public <T> List<T> getChildList(List<T> list, String id) throws Throwable {
        List<T> clist = new ArrayList<T>();
        for (T item : list) {
            String parent = (String) MFReflect.getProperty(item, parentProperty);

            if (MFString.compareNoCase(parent, id)) {
                clist.add(item);
            }

        }
        return clist;
    }

    protected <T> boolean getTree(List<T> allList, MFDataNode parentNode, List<T> childList) throws Throwable {
        for (T item : childList) {
            String id = (String) MFReflect.getProperty(item, idProperty);
            String parentId = (String) MFReflect.getProperty(item, parentProperty);

            String text = (String) MFReflect.getProperty(item, textProperty);
            String data = "";
            String tag = "";
            if (MFString.notNullOrEmpty(dataProperty)) {
                data = (String) MFReflect.getProperty(item, dataProperty);
            }

            if (MFString.notNullOrEmpty(tagProperty)) {
                tag = (String) MFReflect.getProperty(item, tagProperty);
            }


            //MFDebug.println(id);
            MFDataNode node = this.addChildNodeData(parentNode, id, text, data);
            node.setTag(tag);
            List<T> nList = getChildList(allList, id);

            if (nList.size() > 0) getTree(allList, node, nList);
        }
        return true;
    }


    protected MFDataTable getChildTable(MFDataTable table, String id) throws Throwable {

        MFDataTable ctable = new MFDataTable();
        ctable.getColumns().clone(table.getColumns());

        for (MFDataRow row : table.getRows()) {
            if (MFString.compareNoCase(row.getString(parentProperty), id)) {
                ctable.getRows().clone(row);
            }
        }
        return ctable;
    }

    protected boolean createTreeTable(MFDataTable table, MFDataNode parentNode, MFDataTable ctable) throws Throwable {
        for (MFDataRow row : ctable.getRows()) {
            String id = row.getString(idProperty);
            String parentId = row.getString(parentProperty);

            String text = row.getString(textProperty);
            String data = "";
            String tag = "";
            if (MFString.notNullOrEmpty(dataProperty)) {
                data = row.getString(dataProperty);
            }

            if (MFString.notNullOrEmpty(tagProperty)) {
                tag = row.getString(tagProperty);
            }

            //MFDebug.println(id);

            MFDataNode node = this.addChildNodeData(parentNode, id, text, data);
            node.setTag(tag);
            MFDataTable ccTable = getChildTable(table, id);

            if (!ccTable.isEmpty()) {
                createTreeTable(table, node, ccTable);
            }
        }
        return true;
    }


    public <T> boolean createTree(List<T> list) throws Throwable {

        return createTree(list, "root");
    }

    public <T> boolean createTree(List<T> list, String id) throws Throwable {
        List<T> rootlist = getChildList(list, id);
        getTree(list, root, rootlist);
        return true;
    }

    public boolean createTree(MFDataTable table, String id) throws Throwable {
        MFDataTable ctable = getChildTable(table, id);
        createTreeTable(table, root, ctable);
        return true;

    }

    public boolean createTree(MFDataTable table) throws Throwable {
        return createTree(table, "root");
    }


    public void setRoot(MFDataNode root) {
        this.root = root;
    }

    public MFDataNode getRoot() {
        return root;
    }

    public MFDataNode addChildNode(MFDataNode parentNode, String id, String text) {

        return addChildNodeData(parentNode, id, text, null);
    }

    public MFDataNode addChildNodeData(MFDataNode parentNode, String id, String text, Object data) {
        MFDataNode node = new MFDataNode();
        node.setData(data);
        node.setText(text);
        node.setId(id);

        nodeList.add(node);
        if (parentNode != null) {
            node.setParent(parentNode);
            parentNode.getChilds().add(node);

        } else {
            node.setParent(root);
            root.getChilds().add(node);

        }

        return node;
    }

    public MFDataNode addNodeData(MFDataNode node, String id, String text, Object data) {
        if (node.getParent() != null) {
            addChildNodeData(node.getParent(), id, text, data);
        } else {
            new Exception("error root node");
        }
        return null;
    }

    public MFDataNode addPrevNodeData(MFDataNode node, String id, String text, Object data) {
        MFDataNode cnode = addNodeData(node, id, text, data);
        moveTo(cnode, node, true);
        return cnode;
    }

    public void moveTo(MFDataNode nodeA, MFDataNode nodeB, boolean before) {
        int i = 0;
        if (before) {
            i = nodeB.getIndex();
        } else {
            i = nodeB.getIndex() + 1;
        }

        if (nodeA.getParent() == nodeB.getParent()) {
            nodeB.getChilds().set(nodeB.getIndex(), nodeA);
        } else {
            nodeB.getChilds().add(nodeB.getIndex(), nodeA);
            nodeB.getChilds().remove(nodeB);
        }

    }

    public MFDataNode addNextNodeData(MFDataNode node, String id, String text, Object data) {
        MFDataNode cnode = addNodeData(node, id, text, data);
        moveTo(cnode, node, true);
        return cnode;
    }

    public void setIdProperty(String idProperty) {
        this.idProperty = idProperty;
    }

    public String getIdProperty() {
        return idProperty;
    }

    public void setParentProperty(String parentProperty) {
        this.parentProperty = parentProperty;
    }

    public String getParentProperty() {
        return parentProperty;
    }

    public void setDataProperty(String dataProperty) {
        this.dataProperty = dataProperty;
    }

    public String getDataProperty() {
        return dataProperty;
    }

    public void setTextProperty(String textProperty) {
        this.textProperty = textProperty;
    }

    public String getTextProperty() {
        return textProperty;
    }

    public void setNodeList(MFDataNodes nodeList) {
        this.nodeList = nodeList;
    }

    public MFDataNodes getNodeList() {
        return nodeList;
    }

    public void setTagProperty(String tagProperty) {
        this.tagProperty = tagProperty;
    }

    public String getTagProperty() {
        return tagProperty;
    }
}
